<?php
/**
 * 框架核心实例
 *
 * @version $Id: Instance.php 142 2013-10-08 12:17:19Z linsir123 $
 * @package Framework
 */
class Instance
{
	/**
	 * 应用别名
	 * // 用于改变控制器和视图层的目录结构
	 *
	 * @var array
	 */
	public $alias;

	/**
	 * 实例对象集合
	 *
	 * @var array
	 */
	public $instances = array();

	/**
	 * 启动应用程序
	 *
	 * @param string $route 路由信息
	 */
	public function serve($route = null)
	{
		///
		$this->_init();

		///
		$data = $this->getRequest()->parse($route);
		$this->getHook()->activeHook('dispatcher_start', $data);

		///
		list($this->alias, $v) = $data;
		$this->getDispatcher()->gotoCtrl($v[0], $v[1]);

		///
		$this->end();
	}

	/**
	 * 结束应用并输出结果
	 */
	public function end()
	{
		if ($this->isSingleton('View'))
			$this->getView()->render();

		///
		$this->getHook()->activeHook('end');

		///
		exit();
	}

	/**
	 * 返回`配置`管理对象
	 *
	 * @return Config
	 */
	public function getConfig()
	{
		///
		return $this->singleton('Config');
	}

	/**
	 * 返回`勾子`管理对象
	 *
	 * @return Hook
	 */
	public function getHook()
	{
		///
		return $this->singleton('Hook');
	}

	/**
	 * 返回`日志`对象
	 *
	 * @return Log
	 */
	public function getLog()
	{
		///
		return $this->singleton('Log');
	}

	/**
	 * 返回`错误/异常处理`对象
	 *
	 * @return Handler
	 */
	public function getHandler()
	{
		///
		return $this->singleton('Handler');
	}

	/**
	 * 返回`调试`对象
	 *
	 * @return Debugger
	 */
	public function getDebugger()
	{
		///
		return $this->singleton('Debugger');
	}

	/**
	 * 返回`链接请求`对象
	 *
	 * @return Request
	 */
	public function getRequest()
	{
		///
		return $this->singleton('Request');
	}

	/**
	 * 返回`消息派发`对象
	 *
	 * @return Dispatcher
	 */
	public function getDispatcher()
	{
		///
		return $this->singleton('Dispatcher');
	}

	/**
	 * 返回`视图`对象
	 *
	 * @return View
	 */
	public function getView()
	{
		///
		return $this->singleton('View');
	}

	/**
	 * 取得一个存储对象
	 *
	 * @param int $type 存储类型
	 * @param int $index 索引
	 *
	 * @throws Exception
	 * @return mixed
	 */
	public function getStore($type, $index)
	{
		///
		switch ($type) {
			///
			case 1:
				$class = "LpMysql";
				$format = "store.mysql.%s";
				break;

			///
			case 2:
				$class = "LpRedis";
				$format = "store.redis.%s";
				break;

			///
			default:
				throw new Exception("[APP] 存储引擎不存在({$type})");
				break;
		}

		///
		if (! $this->isSingleton($class, $index)) {
			$key = sprintf($format, $index);
			$conf = $this->getConfig()->get($key);
			$params = array($conf);
		}
		else
			$params = null;

		///
		return $this->singleton($class, $params, $index);
	}

	/**
	 * 取得一个插件
	 *
	 * @param string $name 组件名
	 * @param bool $internal 从应用或框架处提供
	 * @param string $relative 用于数据分层或归类(经/纬度)
	 * @param string $prefix 用于避免类名重复冲突
	 *
	 * @return mixed
	 */
	public function getHelper($name, $internal = true, $relative = '', $prefix = 'Helper')
	{
		///
		$class = $this->_import(2, $name,
			$prefix, $relative, $internal ? BASE_DIR : APP_DIR);

		///
		return $this->singleton($class, null);
	}

	/**
	 * 返回一个模型对象
	 *
	 * @param string $name 模型名
	 * @param int $key 同一个类的某个实例(0则返回某个实例, 非0则为某个单例)
	 * @param string $relative 用于数据分层或归类(经/纬度)
	 * @param string $prefix 用于避免类名重复冲突
	 *
	 * @return mixed
	 */
	public function getModel($name, $key = 1, $relative = '', $prefix = 'Model')
	{
		///
		$class = $this->_import(1, $name,
			$prefix, $relative);

		///
		return $key === 0 ?
			$this->newInstance($class, null) :
			$this->singleton($class, null, $key);
	}

	/**
	 * 返回一个数据表模型对象
	 *
	 * @param string $name 模型名
	 * @param string $relative 用于数据分层或归类(经/纬度)
	 * @param string $prefix 用于避免类名重复冲突
	 *
	 * @return mixed
	 */
	public function getDb($name, $relative = '', $prefix = 'Db')
	{
		///
		$class = $this->_import(0, $name,
			$prefix, $relative);

		///
		return $this->singleton($class);
	}

	/**
	 * 判断某个类是否实例化
	 *
	 * @param string $class 类名
	 * @param int $key 同名类时,区间的键值
	 *
	 * @return bool
	 */
	public function isSingleton($class, $key = 0)
	{
		///
		return isset($this->instances[$class][$key]);
	}

	/**
	 * 取得某个类的实例化对象
	 *
	 * @param string $class 类名
	 * @param array $params 类实例化时需要的参数
	 * @param int $key 同一个类的某个实例
	 *
	 * @throws Exception
	 * @return mixed
	 */
	public function singleton($class, $params = array(), $key = 0)
	{
		///
		if ($this->isSingleton($class, $key))
			return $this->instances[$class][$key];

		///
		if (! class_exists($class))
			throw new Exception("[APP] 类不存在({$class})");

		///
		$singleton = $this->newInstance($class, $params);
		$this->instances[$class][$key] = $singleton;

		return $singleton;
	}

	/**
	 * 返回某个类的实例
	 *
	 * @param string $class 类名
	 * @param array $params 类实例化时需要的参数
	 *
	 * @return mixed
	 */
	public function newInstance($class, $params = array())
	{
		///
		if (count($params) == 0)
			return new $class;

		///
		$ref = new ReflectionClass($class);

		return $ref->newInstanceArgs($params);
	}

	/**
	 * 加载类
	 *
	 * @param int $type
	 * @param string $name
	 * @param string $prefix
	 * @param string $relative
	 * @param bool|string $dir
	 *
	 * @return string
	 */
	private function _import($type, $name, $prefix, $relative = '', $dir = APP_DIR)
	{
		///
		static $folders = array(
			0 => 'Db',
			1 => 'Model',
			2 => 'Helper',
		);

		///
		$name = ucfirst($name);
		$format = "%s/" .
			(empty($relative) ? '' : ucfirst($relative) . DS)
			. "%s.php";

		///
		$file = sprintf($format, $folders[$type], $name);

		///
		Load::import($file, $dir);

		///
		return $prefix . $name;
	}

	/**
	 * 初始化
	 */
	private function _init()
	{
		///
		if (function_exists('date_default_timezone_set'))
			date_default_timezone_set('Asia/ShangHai');

		///
		Load::addClassByDir(APP_DIR . "Lib/", array('Init'), 1);

		/// Handler
		$this->getHandler()->run();
	}
}
